package com.demo.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.demo.constant.Constant;
import com.demo.entity.Dictionary;
import com.demo.entity.Message;
import com.demo.entity.Patient;
import com.demo.entity.User;
import com.demo.enums.*;
import com.demo.jwt.JwtTokenUtil;
import com.demo.mapper.DictionaryMapper;
import com.demo.mapper.MessageMapper;
import com.demo.mapper.UserMapper;
import com.demo.response.Result;
import com.demo.service.IMessageService;
import com.demo.service.IRoleService;
import com.demo.websocket.WebSocketServer;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 消息记录表 服务实现类
 *
 * @author zm
 * @since 2020-11-24
 */
@Service
@Slf4j
public class MessageServiceImpl extends ServiceImpl<MessageMapper, Message> implements IMessageService {
    @Resource
    MessageMapper messageMapper;
    @Resource
    UserMapper userMapper;
    @Autowired
    IRoleService roleService;
    @Autowired
    WebSocketServer webSocketServer;
    @Resource
    DictionaryMapper dictionaryMapper;

    /**
     * 更新消息
     *
     * @param message 实体对象
     * @return
     */
    @Override
    public Result updateMessageService(Message message) {
        if (message.getMessageId() == null || message.getUpdatedUserId() == null) {
            return Result.error("主键 ID 或操作人 ID 为空");
        }
        message.setMessageDealTime(new Date());
        updateById(message);
        log.info("更新消息为{}", message);
        QueryWrapper<Message> messageQueryWrapper = new QueryWrapper();
        messageQueryWrapper.eq("message_id", message.getMessageId());
        message = getOne(messageQueryWrapper);
        message.setMessageRank(MessageRankEnum.ADD.getValue());
        log.info("更新消息为{}", message);
        List<String> userList = Arrays.asList(message.getMessageTarget().split(","));
        try {
            webSocketServer.sendToUser2(message, userList);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Result.success(message);
    }

    /**
     * 删除消息
     *
     * @param messageId     消息ID
     * @param deletedUserId 删除人ID
     * @return
     */
    @Override
    public Result deleteMessageService(Integer messageId, Integer deletedUserId) {
        Message message = new Message();
        message.setDeletedTime(new Date());
        message.setMessageId(messageId);
        message.setDeletedUserId(deletedUserId);
        boolean flag = updateById(message);
        if (flag == false) {
            return Result.error(Constant.DB_ERROR);
        }
        return Result.success();
    }

    /**
     * 消息列表
     *
     * @param pageNumber 页码
     * @param pageSize   大小
     * @param status     状态
     * @return
     */
    @Override
    public Result messageServiceListV2(Integer pageNumber, Integer pageSize, Integer status) {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        User user = JwtTokenUtil.decodeTokenUser(request.getHeader("token"));
        Page<Message> page = new Page(pageNumber.intValue(), pageSize.intValue());
        QueryWrapper<Message> messageQueryWrapper = new QueryWrapper();
        if (status != null) {
            messageQueryWrapper.eq("message_status", status);
        }
        messageQueryWrapper.isNull("deleted_time");
        messageQueryWrapper.last(" and string_to_array( message_target, ',' ) @> ARRAY ['" + user.getWorkSn() + "']  order by message_id desc");
        IPage<Message> iPage = messageMapper.selectPage(page, messageQueryWrapper);
        for (Message message : iPage.getRecords()) {
            if (message.getUserId() != null) {
                message.setUserName((userMapper.selectById(message.getUserId())).getUserTrueName());
            }
        }
        return Result.success(iPage);
    }

    /**
     * 发送提醒
     *
     * @param messageType
     * @param patient
     * @param messageSource
     * @param messageContent
     * @param uid
     * @return
     * @throws IOException
     */
    @Override
    public boolean sendMessageNotification(MessageRemindEnum messageType, Patient patient, MessageSourceEnum messageSource, Map<String, Object> messageContent, Integer uid, Date sendTime, Integer doctorAdviceId) throws IOException {
        Message message = new Message();
        message.setMessageType(messageType.getValue());
        message.setCreatedTime(sendTime == null ? new Date() : sendTime);
        message.setUpdatedTime(sendTime == null ? new Date() : sendTime);
        message.setSendTime(sendTime == null ? new Date() : sendTime);
        message.setMessageSource(messageSource.getValue());
        message.setPatientId(patient.getPatientId());
        message.setStatus(MessageStatusEnum.UN_HANDLE.getValue());
        message.setMessageContent(JSONObject.toJSONString(messageContent));
        message.setCreatedUserId(uid);
        if (doctorAdviceId != null) {
            // 医嘱药物提醒消息
            message.setDoctorAdviseId(doctorAdviceId);
        }

        List<String> remindUserWorkSnList = new ArrayList<>();

        log.info("=======>messageType={}", messageType);
        switch (messageType) {
            case PING_GU_REMIND:
                log.info("=======>PING_GU_REMIND={}", messageType);
                remindUserWorkSnList = getRemindUserWorkSnList(messageType, message, patient, 1, "初筛循环提醒", "初筛初始班次", "初筛所有护士", "初筛对象", 2, 2);
                break;
            case ZHEN_DUAN_REMIND:
                log.info("=======>ZHEN_DUAN_REMIND={}", messageType);
                remindUserWorkSnList = getRemindUserWorkSnList(messageType, message, patient, 8, "循环提醒", "提醒班次", "所有医生", "提醒对象", 2, 1);
                break;
            case CHU_ZHI_REMIND:
                log.info("=======>CHU_ZHI_REMIND={}", messageType);
                remindUserWorkSnList = getRemindUserWorkSnList(messageType, message, patient, 12, "循环提醒", "提醒班次", "所有护士", "提醒对象", 2, 2);
                break;
            case YI_ZHU_REMIND:
                log.info("=======>YI_ZHU_REMIND={}", messageType);
                remindUserWorkSnList = getRemindUserWorkSnList(messageType, message, patient, 16, "循环提醒", "提醒班次", "所有医生", "提醒对象", 2, 1);
                break;
            case SHE_BEI_REMIND:
                log.info("=======>SHE_BEI_REMIND={}", messageType);
                remindUserWorkSnList = getRemindUserWorkSnList(messageType, message, patient, 20, "循环提醒", "提醒班次", "所有人员", "提醒对象", 2, 1);
                break;
            case ZONG_JIE_REMIND:
                log.info("=======>ZONG_JIE_REMIND={}", messageType);
                remindUserWorkSnList = getRemindUserWorkSnList(messageType, message, patient, 24, "循环提醒", "提醒班次", "所有医生", "提醒对象", 2, 1);
                break;
            case UN_KNOWN_REMIND:
                log.info("=======>UN_KNOWN_REMIND={}", messageType);
                remindUserWorkSnList = getRemindUserWorkSnList(messageType, message, patient, 1, "复核循环提醒", "复核初始班次", "复核所有医生", "复核对象", 2, 1);
                break;
        }

        save(message);
        webSocketServer.sendToUser2(message, remindUserWorkSnList);
        return true;
    }

    /**
     * 发送提醒
     *
     * @param messageType
     * @param patient
     * @param messageSource
     * @param messageContent
     * @param uid
     * @return
     * @throws IOException
     */
    @Override
    public boolean sendMessageNotification(MessageRemindEnum messageType, Patient patient, MessageSourceEnum messageSource, Map<String, Object> messageContent, Integer uid) throws IOException {
        sendMessageNotification(messageType, patient, messageSource, messageContent, uid, null, null);
        return true;
    }

    /**
     * 班次		   所有			对象						通知提醒
     * 1.正常		是									提醒【用户上班，用户值班】	不提醒【隐身】
     * 2.正常		否			(勾选的角色)				提醒【用户上班，用户值班】	不提醒【隐身】
     * 3.值班		不能操纵		(不能操纵)				提醒【用户值班】	        不提醒【用户上班，隐身】
     * tip: 第 3 条，病人中的医生或护士只要处于值班状态都需要进行消息通知
     *
     * @param messageType
     * @param message
     * @param patient
     * @param parentDictionaryCode
     * @param remindLoop
     * @param banCi
     * @param remindType
     * @param remindUserType
     * @param workStatus
     * @param userType
     * @return
     */
    private List<String> getRemindUserWorkSnList(MessageRemindEnum messageType, Message message, Patient patient, int parentDictionaryCode, String remindLoop, String banCi, String remindType, String remindUserType, int workStatus, int userType) {
        List<String> userWorkSnList = new ArrayList<>();
        Map<String, String> msgNotificationSetting = new HashMap<>();

        QueryWrapper<Dictionary> dictionaryQueryWrapper = new QueryWrapper();
        dictionaryQueryWrapper.select(new String[]{"enumeration_name,enumeration_value"});
        dictionaryQueryWrapper.eq("parent_dictionary_code", Integer.valueOf(parentDictionaryCode));
        List<Dictionary> dictionaries = dictionaryMapper.selectList((Wrapper) dictionaryQueryWrapper);
        for (Dictionary dict : dictionaries) {
            msgNotificationSetting.put(dict.getEnumerationName(), dict.getEnumerationValue());
        }
        log.info("messageType={}------->msgNotificationSetting={}", messageType.getDesc(), JSON.toJSONString(msgNotificationSetting));
        message.setLoop(Integer.parseInt(msgNotificationSetting.get(remindLoop)));

        // 班次是值班，直接从病人元数据对象中获取关联护士或医生工号集合，并查找对应处于值班状态的工作人员进行消息通知
        if ((msgNotificationSetting.get(banCi)).equals(String.valueOf(GlobalMessageBanCiEnum.ZHI_BAN.getValue()))) { // 值班
            userWorkSnList = getPatientRemindUserWorkSnList(messageType, patient);
            userWorkSnList = userWorkSnList.size() == 0 ? userWorkSnList : userMapper.queryRemindUserWordSnList(userWorkSnList, new Integer[]{UserWorkStatusEnum.ZHI_BAN.getValue(), UserWorkStatusEnum.YIN_SHEN.getValue()});
            log.info("班次-值班-messageType={}, 用户列表={}", messageType.getDesc(), JSON.toJSONString(userWorkSnList));
            message.setMessageTarget(String.join(",", userWorkSnList));
            return userWorkSnList;
        }

        if ((msgNotificationSetting.get(remindType)).equals(String.valueOf(GlobalMessageRemindTypeEnum.YES.getValue()))) { //是
            userWorkSnList = getPatientRemindUserWorkSnList(messageType, patient);
            log.info("1班次-正常-是-messageType={}, 用户列表={}", messageType.getDesc(), JSON.toJSONString(userWorkSnList));
        } else {
            try {
                // 处理勾选的角色
                List<String> list = Arrays.asList((msgNotificationSetting.get(remindUserType)).split(","));
                if (list.contains(String.valueOf(RoleEnum.HEAD_NURSE.getValue()))) {
                    userWorkSnList.add(patient.getHeadNurse());
                }
                if (list.contains(String.valueOf(RoleEnum.NURSE_IN_CHARGE.getValue()))) {
                    userWorkSnList.add(patient.getNurseInCharge());
                }
                if (list.contains(String.valueOf(RoleEnum.MEDICAL_LEADER.getValue()))) {
                    userWorkSnList.add(patient.getMedicalLeader());
                }
                if (list.contains(String.valueOf(RoleEnum.DOCTOR_IN_CHARGE.getValue()))) {
                    userWorkSnList.add(patient.getDoctorInCharge());
                }
                log.info("2班次-正常-否-messageType={}, 用户列表={}", messageType.getDesc(), JSON.toJSONString(userWorkSnList));
            } catch (Exception ex) {
                ex.printStackTrace();
            }
        }

        if ((msgNotificationSetting.get(banCi)).equals(String.valueOf(GlobalMessageBanCiEnum.ZHEGN_CHANG.getValue()))) { // 正常
            userWorkSnList = userWorkSnList.size() == 0 ? userWorkSnList : userMapper.queryRemindUserWordSnList(userWorkSnList, new Integer[]{UserWorkStatusEnum.ZHI_BAN.getValue(), UserWorkStatusEnum.ZHENG_CHANG.getValue(), UserWorkStatusEnum.YIN_SHEN.getValue()});
            log.info("3班次-正常-messageType={}, 用户列表={}", messageType.getDesc(), JSON.toJSONString(userWorkSnList));
        }
        message.setMessageTarget(String.join(",", userWorkSnList));
        return userWorkSnList;
    }

    /**
     * 获取原始病人数据对象中关联的医生或护士工号集合
     *
     * @param messageType
     * @param patient
     * @return
     */
    private List<String> getPatientRemindUserWorkSnList(MessageRemindEnum messageType, Patient patient) {
        List<String> userWorkSnList = new ArrayList<>();
        switch (messageType) {
            case PING_GU_REMIND:
            case CHU_ZHI_REMIND:
                List<User> nurses = userMapper.queryUserByUserType(UserTypeEnum.NURSE.getValue());
                userWorkSnList = nurses.stream().map(User::getWorkSn).collect(Collectors.toList());
                break;
            case ZHEN_DUAN_REMIND:
            case ZONG_JIE_REMIND:
            case FU_HE_REMIND:
            case UN_KNOWN_REMIND:
            case YI_ZHU_REMIND:
                List<User> doctors = userMapper.queryUserByUserType(UserTypeEnum.DOCTOR.getValue());
                userWorkSnList = doctors.stream().map(User::getWorkSn).collect(Collectors.toList());
                break;
            case SHE_BEI_REMIND:
                List<User> allUsers = userMapper.queryUserAll();
                userWorkSnList = allUsers.stream().map(User::getWorkSn).collect(Collectors.toList());
                break;
        }
        return userWorkSnList;
    }

    /**
     * 获取原始病人数据对象中关联的医生或护士工号集合
     *
     * @param messageType
     * @param patient
     * @return
     */
//    private List<String> getPatientRemindUserWorkSnList(MessageRemindEnum messageType, Patient patient) {
//        List<String> userWorkSnList = new ArrayList<>();
//        switch (messageType) {
//            case PING_GU_REMIND:
//            case CHU_ZHI_REMIND:
//                userWorkSnList.add(patient.getNurseInCharge());
//                userWorkSnList.add(patient.getHeadNurse());
//                break;
//            case ZHEN_DUAN_REMIND:
//            case ZONG_JIE_REMIND:
//            case FU_HE_REMIND:
//            case UN_KNOWN_REMIND:
//            case YI_ZHU_REMIND:
//                userWorkSnList.add(patient.getDoctorInCharge());
//                userWorkSnList.add(patient.getMedicalLeader());
//                break;
//            case SHE_BEI_REMIND:
//                userWorkSnList.add(patient.getNurseInCharge());
//                userWorkSnList.add(patient.getHeadNurse());
//                userWorkSnList.add(patient.getDoctorInCharge());
//                userWorkSnList.add(patient.getMedicalLeader());
//                break;
//        }
//        return userWorkSnList;
//    }
}
